//
//  GenericsExample.swift
//  SwiftCode
//
//  Created by yuhus on 2024/1/2.
//

import Foundation
import Utility

class GenericsExample: ListViewController {
  override func getItemCount() -> Int {
    data.count
  }
  
  override func getItem(_ indexPath: IndexPath) -> Item {
    data[indexPath.row]
  }
  
  private lazy var data: [Item] = [
    .init(title: "泛型类型", description: "Stack 后进先出", action: testStack),
    .init(title: "类型约束实践", description: "在数组中找出元素", action: actionTypeConstraints),
    .init(title: "关联类型", description: "在关联类型约束里使用协议，返回协议类型", action: testSuffix),
    .init(title: "泛型下标", description: "下标方法，接收一个索引的集合，返回每一个索引所在的值的数组", action: testSubscript),
  ]
}

private func testStack() {
  var stackOfStrings = Stack<String>()
  stackOfStrings.push("uno")
  stackOfStrings.push("dos")
  stackOfStrings.push("tres")
  stackOfStrings.push("cuatro")
  // 栈中现在有 4 个字符串
  let fromTheTop = stackOfStrings.pop()
  // fromTheTop 的值为“cuatro”，现在栈中还有 3 个字符串
  print(fromTheTop)
}

private extension Stack {
  var topItem: Element? {
    return items.isEmpty ? nil : items[items.count - 1]
  }
}

func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
  for (index, value) in array.enumerated() {
    if value == valueToFind {
      return index
    }
  }
  return nil
}

private func actionTypeConstraints() {
  let doubleIndex = findIndex(of: 9.3, in: [3.14159, 0.1, 0.25])
  // doubleIndex 类型为 Int?，其值为 nil，因为 9.3 不在数组中
  debugPrint(doubleIndex as Any)
  
  let stringIndex = findIndex(of: "Andrea", in: ["Mike", "Malcolm", "Andrea"])
  // stringIndex 类型为 Int?，其值为 2
  debugPrint(stringIndex as Any)
}

// MARK: 关联类型实践
protocol Container {
  associatedtype Item: Equatable // 给关联类型添加约束
  mutating func append(_ item: Item)
  var count: Int { get }
  subscript(i: Int) -> Item { get }
}

extension Stack: Container where Element: Equatable {
  typealias Item = Element
  
  typealias Iterator = Array
  
  mutating func append(_ item: Element) {
    self.push(item)
  }
  
  var count: Int {
    return items.count
  }
  
  subscript(i: Int) -> Element {
    return items[i]
  }
  
  func makeIterator() -> Array<Element> {
    return Array()
  }
}

// MARK: 在关联类型约束里使用协议


/// 返回容器中从后往前给定数量的元素
/// 
/// Suffix 拥有两个约束
/// - 必须遵循 SuffixableContainer 协议
/// -  Item 类型必须是和容器里的 Item 类型相同
protocol SuffixableContainer: Container {
  associatedtype Suffix: SuffixableContainer where Suffix.Item == Item
  func suffix(_ size: Int) -> Suffix
}

extension Stack: SuffixableContainer where Element: Equatable {
  //  typealias Suffix = Stack
  
  func suffix(_ size: Int) -> Stack {
    var result = Stack()
    for index in (count - size) ..< count {
      result.append(self[index])
    }
    return result
  }
  // 推断 suffix 结果是Stack。
}

private func testSuffix() {
  var stackOfInts = Stack<Int>()
  stackOfInts.append(10)
  stackOfInts.append(20)
  stackOfInts.append(30)
  let suffix = stackOfInts.suffix(2)
  // suffix 包含 20 和 30
  debugPrint(suffix)
}

// MARK: 具有泛型 Where 子句的关联类型
protocol IteratorContainer: Container {
  associatedtype Iterator: IteratorProtocol where Iterator.Element == Item
  func makeIterator() -> Iterator
}

// MARK: 泛型下标
extension Container {
  subscript<Indices: Sequence>(indices: Indices) -> [Item] where Indices.Iterator.Element == Int {
    var result: [Item] = []
    for index in indices {
      result.append(self[index])
    }
    return result
  }
}

private func testSubscript() {
  var stackOfStrings = Stack<String>()
  stackOfStrings.push("uno")
  stackOfStrings.push("dos")
  stackOfStrings.push("tres")
  stackOfStrings.push("cuatro")
  // 栈中现在有 4 个字符串
  
  let result = stackOfStrings[[0,1,2]]
  debugPrint(result)
  // ["uno", "dos", "tres"]
}
